#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <event.h>
#include <netinet/in.h>

#include "net.h"
#include "list.h"
#include "colorido.h"

	int
net_listen (int port)
{
	struct sockaddr_in sa;
	int on = 1, s = -1;

	if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1)
	{
		return FALSE;
	}
	if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1)
	{
		close (s);
		return FALSE;
	}

	sa.sin_family = AF_INET;
	sa.sin_port = htons (port);
	sa.sin_addr.s_addr = htonl (INADDR_ANY);
	if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) == -1)
	{
		close (s);
		return FALSE;
	}
	if (listen (s, 10) == -1)
	{
		close (s);
		return FALSE;
	}
	return s;

}

void net_read(int fd,short ev,void *arg){
	coner *ncon = (coner *)arg;
	char mread[NET_READ_SIZE];
	qsend *q = NULL;
	int ret;

	if(ev & EV_TIMEOUT){
		close(ncon->sock);
		free_coner(ncon);
		return;
	}
	
	ret = recv(fd,mread,NET_READ_SIZE,MSG_NOSIGNAL);

	if(ret<=0){
		close(ncon->sock);
		free_coner(ncon);
		return;
	}

	q = malloc(sizeof(qsend));
	q->req = strdup(mread);
	q->con = ncon;

	pthread_mutex_lock(&ncon->base->mutex);
	queue_enqueue(ncon->base->que,q);
	pthread_mutex_unlock(&ncon->base->mutex);
	pthread_cond_signal(&ncon->base->cond);

}

void net_accept(int fd,short ev,void *arg){
	ctrler *base = (ctrler *)arg;
	int nsock;
	socklen_t l = sizeof(struct sockaddr_in);
	struct sockaddr_in sa;
	coner *ncon;

	nsock = accept(fd,(struct sockaddr *)&sa,&l);
	if(nsock == -1)
		return;

	ncon = alloc_coner();
	if(ncon == NULL){
		close(nsock);
		return;
	}
	ncon->sock = nsock;
	ncon->base = base;
	event_set(&ncon->ev,ncon->sock,EV_READ|EV_PERSIST,net_read,ncon);
	event_add(&ncon->ev,NULL);
	//event_add(&ncon->ev,&ncon->tv);

}

int net_init(ctrler *base){
	int i;
	if((i=net_listen(1122))==FALSE)
		return FALSE;
	base->sock = i;
	event_set(&base->ev,base->sock,EV_READ|EV_PERSIST,net_accept,base);
	event_add(&base->ev,NULL);
	return TRUE;
}
	
